#ifndef __SHARED_PTR_H__
#define __SHARED_PTR_H__

namespace Boss
{

  template <typename T>
  class SharedPtr
  {
  public:
    explicit SharedPtr(T *ptr = 0)
      : Ptr(ptr)
      , Counter(ptr ? new unsigned long(1) : 0)
    {
    }
    template <typename TOther>
    explicit SharedPtr(TOther *ptr)
      : Ptr(ptr)
      , Counter(ptr ? new unsigned long(1) : 0)
    {
    }
    SharedPtr(const SharedPtr &ptr)
      : Ptr(ptr.Ptr)
      , Counter(ptr.Counter)
    {
      if (Counter)
        (*Counter)++;
    }
    template <typename TOther>
    SharedPtr(const SharedPtr<TOther> &ptr)
      : Ptr(ptr.Ptr)
      , Counter(ptr.Counter)
    {
      if (Counter)
        (*Counter)++;
    }
    SharedPtr& operator = (T *ptr)
    {
      SharedPtr Tmp(ptr);
      Swap(Tmp);
      return *this;
    }
    template <typename TOther>
    SharedPtr& operator = (TOther *ptr)
    {
      SharedPtr<T> Tmp(ptr);
      Swap(Tmp);
      return *this;
    }
    SharedPtr& operator = (const SharedPtr &ptr)
    {
      SharedPtr Tmp(ptr);
      Swap(Tmp);
      return *this;
    }
    template <typename TOther>
    SharedPtr& operator = (const SharedPtr<TOther> &ptr)
    {
      SharedPtr Tmp(ptr);
      Swap(Tmp);
      return *this;
    }
    ~SharedPtr()
    {
      Release();
    }
    void Release()
    {
      if (Counter && !--(*Counter))
      {
        delete Counter;
        delete Ptr;
      } 
      Counter = 0;
      Ptr = 0;
    }
    T* operator -> () const
    {
      return Ptr;
    }
    void Swap(SharedPtr &ptr)
    {
      T *CurPtr = Ptr;
      Ptr = ptr.Ptr;
      ptr.Ptr = CurPtr;
      unsigned long *CurCounter = Counter;
      Counter = ptr.Counter;
      ptr.Counter = CurCounter;
    }
    T* Get() const
    {
      return Ptr;
    }
    template <typename TOther>
    void Reset(TOther *ptr)
    {
      SharedPtr NewPtr(ptr);
      Swap(NewPtr);
    }

  private:
    T *Ptr;
    unsigned long *Counter;
    template <typename> friend class SharedPtr;
  };

}

#endif  // !__SHARED_PTR_H__
